//
//  DispatchExample.swift
//  SwiftCode
//
//  Created by yuhus on 2023/8/25.
//

import Foundation

class DispatchExample: ListViewController {
  override func getItemCount() -> Int {
    data.count
  }
  
  override func getItem(_ indexPath: IndexPath) -> Item {
    data[indexPath.row]
  }
  
  private lazy var data: [Item] = [
    .init(title: "SeriallyQueue", description: "sync 当前线程，async和async-sync 在其他线程", action: testSeriallyQueue),
    .init(title: "ConcurrentQueue", description: "sync 当前线程，async和async-sync 在其他线程", action: testConcurrentQueue),
    .init(title: "DispatchQueue", description: "并发执行，并指定执行的次数", action: testDispatchQueue),
    .init(title: "DispatchWorkItem", description: "任务依赖，UI 更新依赖后台数据", action: testDispatchWorkItem),
    .init(title: "DispatchGroup", description: "指定超时时间，判断是否完成任务", action: testDispatchGroup),
    .init(title: "DispatchSemaphore", description: "设置最大并发数", action: testDispatchSemaphore),
    .init(title: "HandleConcurrent", description: "处理并发问题", action: handleConcurrent),
  ]
  
  private let seriallyQueue = DispatchQueue(label: "com.coder.dispatch.serially")
  private let name = "张三"
  private lazy var workItem = DispatchWorkItem { Timber.d("名称:", "\(self.name)") }
  private lazy var workBlock = { Timber.d("名称:", "\(self.name)") }
  
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    seriallyQueue.async {
      Timber.d("名称:", self.name)
    }
    let block = {
      Timber.d("名称:", self.name)
    }
    block()
    
    // 循环引用
//    seriallyQueue.async(execute: workItem)
//    workBlock()
  }
}

/// 串行队列
private func testSeriallyQueue() {
  let seriallyQueue = DispatchQueue(label: "serially")
  
  seriallyQueue.sync { // 其它线程
    Timber.d("serially.sync")
  }
  DispatchQueue.global().async {
    seriallyQueue.sync { // 其它线程
      Timber.d("global.async-serially.sync")
    }
  }
  for i in 1...5 {
    seriallyQueue.async { // 其它线程
      Timber.d("serially.async", i)
    }
  }
}

/// 并发队列
private func testConcurrentQueue() {
  let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
  
  concurrentQueue.sync { // 当前线程
    Timber.d("concurrent.sync")
  }
  DispatchQueue.global().async {
    concurrentQueue.sync { // 其它线程
      Timber.d("global.async-concurrent.sync")
    }
  }
  for i in 1...5 {
    concurrentQueue.async { // 其它线程
      Timber.d("concurrent.async", i)
    }
  }
}

private func testDispatchQueue() {
  // 将单个块提交到调度队列并使该块执行指定的次数。
  DispatchQueue.concurrentPerform(iterations: 5) { i in
    Timber.d("concurrentPerform", i)
  }
}

private func testDispatchWorkItem() {
  let queue = DispatchQueue(label: "background")
  // 后台任务
  let backgroundWorkItem = DispatchWorkItem {
    Timber.d("执行后台任务")
  }
  // UI更新任务
  let updateUIWorkItem = DispatchWorkItem {
    Timber.d("执行 UI 刷新")
  }
  // backgroundWorkItem 完成后通知 updateUIWorkItem 在主队列 DispatchQueue.main 执行
  backgroundWorkItem.notify(queue: .main, execute: updateUIWorkItem)
  // 添加 backgroundWorkItem 到队列
  queue.async(execute: backgroundWorkItem)
}

private func testDispatchGroup() {
  let group = DispatchGroup()
  let queue = DispatchQueue.global(qos: .userInitiated)
  
  queue.async(group: group) {
    Timber.d("开始任务1")
    Thread.sleep(until: Date().addingTimeInterval(5)) // a
    Timber.d("结束任务1")
  }
  queue.async(group: group) {
    Timber.d("开始任务2")
    Thread.sleep(until: Date().addingTimeInterval(2)) // b
    Timber.d("结束任务2")
  }
  if group.wait(timeout: .now() + 3) == .timedOut { // c
    Timber.d("啊！我等不下去了！😭")
  } else {
    Timber.d("所有任务都已经完成😌")
  }
}

/// 信号量：最大并发数
private func testDispatchSemaphore() {
  let semaphore = DispatchSemaphore(value: 3)
  let queue = DispatchQueue.global(qos: .userInitiated)
  
  for i in 1...10 {
    queue.async {
      semaphore.wait() // Semaphore计数+1
      Timber.d("正在下载第\(i)张图")
      // 模拟网络等待
      Thread.sleep(forTimeInterval: 2)
      Timber.d("第\(i)张图已下载")
      semaphore.signal() // Semaphore计数-1
    }
  }
}

/// a. 串行线程访问
private class CounterA {
  private let threadSafeCountQueue = DispatchQueue(label: "...") // 默认串行线程
  private var _count = 0
  public var count: Int {
    get {
      return threadSafeCountQueue.sync { return _count }
    }
    set {
      threadSafeCountQueue.sync { _count = newValue }
    }
  }
}

/// b. Thread Barrier
private class CounterB {
  private let threadSafeCountQueue = DispatchQueue(label: "...", attributes: .concurrent)
  private var _count = 0
  public var count: Int {
    get {
      return threadSafeCountQueue.sync { return _count }
    }
    set {
      threadSafeCountQueue.async(flags: .barrier) { self._count = newValue }
    }
  }
}

private func handleConcurrent() {
  // 如果CounterA为struct，则countA.count < 10
  var count = 0
  let counterA = CounterA()
  let counterB = CounterB()
  
  let group = DispatchGroup()
  let queue = DispatchQueue(label: "com.gcd.concurrent", attributes: .concurrent)
  
  let iterations = 1000
  for _ in 1...iterations {
    queue.async(group: group) {
      count += 1
    }
  }
  for _ in 1...iterations {
    queue.async(group: group) {
      counterA.count += 1
    }
  }
  for i in 1...iterations {
    queue.async(group: group) {
//      counterB.count += 1 // TODO: 无法运行
      counterB.count = i
    }
  }
  
  // 只能保证不崩溃，但不能保证总和值
  group.notify(queue: queue) {
    Timber.d("count: \(count)")
    Timber.d("counterA.count: \(counterA.count)")
    Timber.d("counterB.count: \(counterB.count)")
  }
}
